<?php

namespace IYUU\sdk\CoolQ\Modules\userapi;

use IYUU\sdk\CoolQ\Context;
use IYUU\sdk\CoolQ\Event\Message as EventMessage;
use IYUU\sdk\CoolQ\ModulesProcessor;
use UserApiReplyModel;

/**
 * Class processor
 * @package IYUU\sdk\CoolQ\Modules\userapi
 */
class processor extends ModulesProcessor
{
    /**
     * 用户API，接口缓存KEY定义
     */
    const USER_API_CACHE_KEY = 'CoolQ:Modules:UserApi:{api_url}:msg_{hash}';

    /**
     * 应答方法 （抽象方法，子类实现）
     * @param Context $context
     * @param EventMessage $msgObj
     * @return mixed
     */
    public function respond(Context $context, EventMessage $msgObj)
    {
        // 1.取消息、取Session
        $message = $context->get('message');
        $session_key = Context::moduleRuleKeywordSession;
        $ruleKeyword = $context->getSession($session_key);
        $rid = $ruleKeyword['rid'];

        // 2.查表，得到待调用的接口
        $reply = UserApiReplyModel::where('rid', $rid)->findOrEmpty();
        if ($reply->isEmpty()) {
            return null;
        }
        $item = $reply->toArray();
        $item['message'] = $message;    // 发来的文本消息
        $item['context'] = $context;    // 上下文对象
        $item['msgObj'] = $msgObj;     // 消息事件对象
        $item['regex_matches'] = $ruleKeyword['regex_matches'] ?? [];

        // 3.查询缓存
        if (!empty($item['cache_expire'])) {
            $cache_key = $this->getCacheKey($item['api_url'], sha1($message));
            if ($result = Context::getCache($cache_key)) {
                return $result;
            }
        }

        // 4.检查流控
        if (!empty($item['limited'])) {
            $cache_key = $this->getCacheKey($item['api_url'], 'limited');
            if ($result = Context::getCache($cache_key)) {
                return $msgObj->isPrivate() ? $result : EventMessage::replyGroup($result, false, true);
            }
        }

        // 5.判断api类型，调用具体的接口
        if (stripos($item['api_url'], 'https://') === 0 || stripos($item['api_url'], 'http://') === 0) {
            // 远程
            $result = $this->procRemote($item);
        } else {
            // 本地
            $result = $this->procLocal($item);
        }

        // 6.1 非空，返回内容
        if (!empty($result)) {
            // 6.1.1 设置缓存
            if (!empty($item['cache_expire'])) {
                $cache_key = $this->getCacheKey($item['api_url'], sha1($message));
                Context::setCache($cache_key, $result . PHP_EOL . 'Cache：' . date('H:i:s'), $item['cache_expire']);
            }
            // 6.1.2 设置流控
            if (!empty($item['limited'])) {
                $cache_key = $this->getCacheKey($item['api_url'], 'limited');
                Context::setCache($cache_key, '触发接口流量限制，请在指定时间后调用。limited：' . date('H:i:s', time() + $item['limited']), $item['limited']);
            }

            return $result;
        }

        // 6.2 空，返回默认
        if (!empty($item['description'])) {
            $result = $item['description'];
            return $msgObj->isPrivate() ? $result : EventMessage::replyGroup($result, false, true);
        }

        return null;
    }

    /**
     * 获取缓存key
     * @param string $api_url
     * @param string $hash
     * @return string
     */
    private function getCacheKey(string $api_url, string $hash): string
    {
        $replace = [
            '{api_url}' => $api_url,
            '{hash}' => $hash
        ];
        return strtr(static::USER_API_CACHE_KEY, $replace);
    }

    /**
     * 调用本地接口
     * @param array $item
     * @return string
     */
    private function procLocal(array $item): string
    {
        $local = basename($item['api_url']);
        $file = __DIR__ . '/api/' . $local;
        if (!file_exists($file)) {
            return '';
        }
        // 将数组键名作为变量名，如果有冲突，则覆盖已有的变量
        extract($item, EXTR_OVERWRITE);
        unset($item);
        ob_start();
        include $file;
        return ob_get_clean();
    }

    /**
     * 调用远程接口
     * @param array $item
     * @return string
     */
    private function procRemote(array $item): string
    {
        return __METHOD__;
    }
}
